<script setup lang="ts">
import type { Ref } from 'vue'
import { getCurrentInstance, onMounted, ref, watch } from 'vue'
import Copy from '@/components/chat/icons/Copy.vue'
import Retry from '@/components/chat/icons/Retry.vue'
import {
  chat,
  createHistory,
  deleteHistory,
  disposeStream,
  getAgentList,
  getConfig,
  getHistoryList,
  streamChat,
  updateHistory,
  uploadFileUrl
} from '@/api/chat.js'
import type {
  IAgent,
  IChatRequest,
  IConfig,
  IFile,
  IHistory,
  IInputTool,
  IMessage
} from '@/types/chat'
import { copyText, formatDate } from '@/utils/common'
import Thinking from '@/components/chat/Thinking.vue'
import UserChatContent from '@/components/chat/chatContent/UserChatContent.vue'
import AnswerChatContent from '@/components/chat/chatContent/AnswerChatContent.vue'
import Agent from '@/components/chat/icons/Agent.vue'
import Menu from '@/components/chat/icons/Menu.vue'
import Delete from '@/components/chat/icons/Delete.vue'
import Send from '@/components/chat/icons/Send.vue'
import Stop from '@/components/chat/icons/Stop.vue'
import Message from '@/components/chat/icons/Message.vue'
import Attach from '@/components/chat/icons/Attach.vue'
import Online from '@/components/chat/icons/Online.vue'
import DeepThink from '@/components/chat/icons/DeepThink.vue'
import SimpleDelete from '@/components/chat/icons/SimpleDelete.vue'

const internalInstance = getCurrentInstance()

const props = defineProps({
  name: {
    type: String,
    required: true
  }
})
const config: Ref<IConfig> = ref({
  name: props.name
})
const tabs = ref([
  {
    name: '智能体',
    key: 'agent',
    showFlag: false
  },
  {
    name: '历史记录',
    key: 'history',
    showFlag: false
  }
])
const inputTools: Ref<IInputTool[]> = ref([
  {
    name: '附件',
    showFlag: false,
    active: false,
    icon: Attach,
    click: function () {
      triggerFileInput()
    }
  },
  {
    name: '深度思考',
    showFlag: false,
    active: false,
    icon: DeepThink,
    click: function () {
      this.active = !this.active
    }
  },
  {
    name: '联网',
    showFlag: false,
    active: false,
    icon: Online,
    click: function () {
      this.active = !this.active
    }
  }
])
const currentTab = ref('agent')
const agentList: Ref<IAgent[]> = ref([])
const historyList: Ref<IHistory[]> = ref([])
const messages = ref<IMessage[]>([])
const inputMessage = ref('')
const currentAgentId = ref('')
const currentHistory: Ref<IHistory | null> = ref(null)
const isShowMenu = ref(false)
const isLoading = ref(false)
const isStreaming = ref(false)

onMounted(async () => {
  initMenu()
  await initConfig()
  if (config.value.multipleAgentFlag) {
    await initAgentList()
    if (agentList.value && agentList.value.length > 0) {
      currentAgentId.value = agentList.value[0].id
    }
  }
  if (config.value.historyFlag) {
    await initHistoryList()
  }
})
const initMenu = () => {
  resize()
  window.onresize = () => {
    return (() => {
      resize()
    })()
  }
  const chatMenu = document.querySelector('.chat-menu')!
  const menuBtn = document.querySelector('.chat-title-menu')!
  document.addEventListener('click', (event: MouseEvent) => {
    const screenWidth =
      window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
    if (screenWidth > 768) {
      return
    }
    const flag =
      chatMenu === event.target ||
      chatMenu!.contains(event.target as Node) ||
      menuBtn === event.target ||
      menuBtn!.contains(event.target as Node)
    if (!flag) {
      isShowMenu.value = false
    }
  })
}
const resize = () => {
  const screenWidth =
    window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
  isShowMenu.value = screenWidth > 768
}
const errContent = '网络连接失败'
const initAgentList = async () => {
  const response = await getAgentList(props.name, {
    page: 1,
    pageSize: 100
  })
  if (!response.ok) {
    errMessage(errContent)
  }
  agentList.value = await response.json()
}
const initHistoryList = async () => {
  const response = await getHistoryList(props.name, {
    page: 1,
    pageSize: 100
  })
  if (!response.ok) {
    errMessage(errContent)
  }
  historyList.value = await response.json()
  initHistorySave()
}
const historyInterval = ref()
const initHistorySave = () => {
  if (historyInterval.value) {
    clearInterval(historyInterval.value)
  }
  historyInterval.value = setInterval(() => {
    console.log(currentHistory.value)
    if (currentHistory.value && currentHistory.value.id) {
      currentHistory.value.messageList = messages.value
      updateHistory(props.name, currentHistory.value)
    }
  }, 1000)
}
const selectHistory = (history: IHistory) => {
  currentHistory.value = null
  messages.value = history.messageList
  currentHistory.value = history
}
const removeHistory = async (history: IHistory) => {
  const response = await deleteHistory(props.name!, history.id)
  if (!response.ok) {
    alert('删除失败')
  } else {
    historyList.value = historyList.value.filter(item => item.id !== history.id)
    if (currentHistory.value && currentHistory.value.id === history.id) {
      currentHistory.value = null
      messages.value = []
    }
  }
}
watch(
  () => currentAgentId.value,
  () => {
    currentHistory.value = null
    initHistorySave()
    if (agentList.value.length === 0) {
      initMessages()
      return
    }
    const agent = agentList.value.find(item => item.id === currentAgentId.value)
    if (!agent) {
      return
    }
    config.value = agent.config
    initMessages()
  }
)
const initMessages = () => {
  messages.value = []
  createPromptMessage()
}
const initConfig = async () => {
  if (!props.name) {
    return
  }
  isLoading.value = true
  const response = await getConfig(props.name)
  const json = await response.json()
  Object.assign(config.value, json)
  console.log(config.value)
  if (config.value.multipleAgentFlag) {
    tabs.value[0].showFlag = true
  }
  if (config.value.historyFlag) {
    tabs.value[1].showFlag = true
  }
  inputTools.value.forEach((item: IInputTool) => {
    if (item.name === '联网') {
      item.showFlag = !!config.value.netQueryFlag
    }
    if (item.name === '深度思考') {
      item.showFlag = !!config.value.deepThinkFlag
    }
    if (item.name === '附件') {
      item.showFlag = !!config.value.attachFlag
    }
  })
  if (!config.value.multipleAgentFlag) {
    initMessages()
  }
}
const scrollerTimeout: Ref<any> = ref(null)
const autoScroller = () => {
  const height = 50
  const element = document.querySelector('.messages-container')!
  if (
    element.scrollHeight - element.clientHeight !== 0 &&
    element.scrollHeight - element.scrollTop - element.clientHeight <= height
  ) {
    if (!scrollerTimeout.value) {
      scrollerTimeout.value = setTimeout(() => {
        element.scrollTo({ top: element.scrollHeight, behavior: 'smooth' })
        internalInstance!.proxy!.$forceUpdate()
        clearTimeout(scrollerTimeout.value)
        scrollerTimeout.value = null
      }, 10)
    }
  }
}
const errMessage = (content?: string, message?: IMessage) => {
  if (!content) {
    content = errContent
  }
  if (message) {
    message.content = content
    return
  }
  addMessage(content, 'assistant')
}
const addMessage = (content: string, role: 'user' | 'assistant', body?: IChatRequest) => {
  const promptMessage: IMessage = {
    role: role,
    content: content,
    body: body,
    timestamp: new Date()
  }
  messages.value.push(promptMessage)
  autoScroller()
  return promptMessage
}
const createPromptMessage = () => {
  if (!config.value.prompt) {
    return
  }
  isLoading.value = true
  setTimeout(() => {
    addMessage(config.value.prompt!, 'assistant')
    isLoading.value = false
  }, 500)
}
const sendMessage = async (message?: IMessage, addFlag: boolean = true) => {
  let currentMessage = message
  if (!currentMessage) {
    currentMessage = {
      role: 'user',
      content: inputMessage.value,
      body: getChatBody(),
      timestamp: new Date()
    }
  }
  if (!currentMessage || isLoading.value) {
    return
  }
  if (addFlag) {
    addMessage(currentMessage.content, 'user', currentMessage.body)
  }
  if (!currentHistory.value) {
    const response = await createHistory(props.name, {
      id: '',
      agentId: currentAgentId.value,
      title: '新的对话',
      messageList: messages.value
    })
    currentHistory.value = (await response.json()) as IHistory
    historyList.value.push(currentHistory.value)
  }
  if (config.value.streamFlag) {
    await getStreamMessage(currentMessage!)
  } else {
    await getMessage(currentMessage!)
  }
}
const getMessage = async (message: IMessage) => {
  if (isLoading.value) {
    return
  }
  if (!config.value.name) {
    await initConfig()
  }
  if (!config.value.name) {
    return
  }
  isLoading.value = true
  internalInstance!.proxy!.$forceUpdate()

  const response = await chat(props.name!, message.body!).finally(() => {
    isLoading.value = false
    focusInput()
  })
  if (!response.ok) {
    errMessage('网络连接失败')
    return
  }
  const data = await response.text()
  console.log(data)
  addMessage(data, 'assistant')
}

const cancelStream = ref(false)
const streamId = ref('')
const getStreamMessage = async (message: IMessage) => {
  isLoading.value = true
  const controller = new AbortController()
  const signal = controller.signal
  const response = await streamChat(props.name!, message.body!, signal).finally(() => {
    isLoading.value = false
  })
  if (!response.ok) {
    errMessage('网络连接失败')
    return
  }
  const headers = response.headers
  streamId.value = headers.get('X-Stream-Id') || ''
  const reader = response.body!.getReader()!
  let decoder = new TextDecoder()
  const assistantMessage: IMessage = addMessage('', 'assistant')
  isStreaming.value = true
  let result = true
  let interval = null
  while (result) {
    const { done, value } = await reader.read()
    if (!interval) {
      interval = setInterval(
        () => {
          internalInstance!.proxy!.$forceUpdate()
          autoScroller()
        },
        config.value.frame ? config.value.frame : 50
      )
    }
    if (done) {
      result = false
      isStreaming.value = false
      clearInterval(interval)
      internalInstance!.proxy!.$forceUpdate()
      focusInput()
      break
    } else if (cancelStream.value) {
      result = false
      controller.abort()
      if (streamId.value) {
        disposeStream(config.value.name!, streamId.value).then(() => {
          console.log('cancel stream success')
        })
      }
      isStreaming.value = false
      clearInterval(interval)
      cancelStream.value = false
      focusInput()
      break
    }
    assistantMessage.content += decoder.decode(value)
  }
}

const getChatBody = () => {
  const body = {
    message: inputMessage.value,
    agentId: currentAgentId.value,
    deepThink: false,
    netQuery: false,
    files: uploadFiles.value
  }
  for (const tool of inputTools.value) {
    if (tool.active) {
      if (tool.name === '联网') {
        body.netQuery = true
      }
      if (tool.name === '深度思考') {
        body.deepThink = true
      }
    }
  }
  uploadFiles.value = []
  inputMessage.value = ''
  return body
}

const stopMessage = () => {
  cancelStream.value = true
}

const handleKeyPress = (event: KeyboardEvent) => {
  if (event.key === 'Enter' && !event.shiftKey) {
    event.preventDefault()
    sendMessage()
  }
}
const showRetry = (index: number) => {
  return index === messages.value.length - 1 && index !== 0
}
const retry = () => {
  messages.value.pop()
  const message = messages.value[messages.value.length - 1]
  sendMessage(message, false)
}
const focusInput = () => {
  setTimeout(() => {
    document.querySelector('textarea')?.focus()
  }, 500)
}
const copyMessageContent = (content: string) => {
  copyText(content).then(() => {
    alert('复制成功')
  })
}
const uploadFiles: Ref<IFile[]> = ref([])
const fileInput = ref()
const triggerFileInput = () => {
  fileInput.value.click()
}
const handleFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files) {
    const files = Array.from(target.files)
    handleFiles(files)
    target.value = ''
  }
}
const handleFiles = (files: File[]) => {
  files.forEach(oFile => {
    const isFileExist = uploadFiles.value.some(
      existingFile =>
        existingFile.file!.name === oFile.name && existingFile.file!.size === oFile.size
    )
    if (!isFileExist) {
      // 上传文件
      const file: IFile = {
        id: '',
        name: oFile.name,
        type: oFile.type,
        size: oFile.size,
        file: oFile,
        status: 'uploading',
        progress: 0
      }
      uploadFiles.value.push(file)
      uploadFileWithProgress(props.name, file)
        .then(res => {
          const data = JSON.parse(res)
          Object.assign(file, data)
          file.status = 'success'
          internalInstance!.proxy!.$forceUpdate()
          console.log('文件上传成功:', data)
        })
        .catch(error => {
          file.status = 'error'
          internalInstance!.proxy!.$forceUpdate()
          console.error('文件上传失败: ', file.name)
          alert('上传失败')
        })
    } else {
      console.warn(`文件 "${oFile.name}" 已存在`)
    }
  })
}
const uploadFileWithProgress = (name: string, file: IFile) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()

    // 监听上传进度事件
    xhr.upload.addEventListener('progress', event => {
      if (event.lengthComputable) {
        const progress = Math.round((event.loaded / event.total) * 100)
        file.progress = progress
        internalInstance!.proxy!.$forceUpdate()
        console.log(`上传进度: ${progress}%`)
      }
    })

    // 处理请求完成的情况
    xhr.addEventListener('load', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response)
      } else {
        file.progress = 0
        reject(new Error(`上传失败，状态码: ${xhr.status}`))
      }
    })

    // 处理请求错误的情况
    xhr.addEventListener('error', () => {
      reject(new Error('上传过程中发生错误'))
    })

    // 处理请求被中止的情况
    xhr.addEventListener('abort', () => {
      reject(new Error('上传被中止'))
    })

    // 发送请求
    xhr.open('POST', uploadFileUrl(props.name), true)
    const formData = new FormData()
    formData.append('file', file.file as Blob)
    xhr.send(formData)
  })
}
const handleFileRemove = (file: IFile) => {
  uploadFiles.value = uploadFiles.value.filter(item => item.id !== file.id)
}
</script>

<template>
  <div class="chat-container">
    <div
      v-if="config.historyFlag || config.multipleAgentFlag"
      :class="['chat-menu', isShowMenu ? '' : 'hidden']"
      ref="chatMenu"
    >
      <div class="chat-menu-tabs list">
        <template v-for="tab in tabs">
          <div
            v-if="tab.showFlag"
            :class="['chat-menu-title', currentTab === tab.key ? 'active' : '']"
            @click="() => (currentTab = tab.key)"
          >
            {{ tab.name }}
          </div>
        </template>
      </div>
      <div
        class="list agent-list"
        v-if="currentTab === 'agent' && config.multipleAgentFlag && agentList.length > 1"
      >
        <slot name="agent-list" :agentList="agentList" :currentId="currentAgentId">
          <div
            :class="['agent-item', currentAgentId === agent.id ? 'active' : '']"
            v-for="(agent, index) in agentList"
            :key="index"
            @click="() => (currentAgentId = agent.id)"
          >
            <slot name="agent-item" :agent="agent">
              <div class="agent-item-icon">
                <img v-if="agent.icon" :src="agent.icon" alt="" />
                <Agent v-else class="default-icon" />
              </div>
              <div class="agent-item-content">
                <div class="agent-item-name">
                  {{ agent.config.name }}
                </div>
                <div class="agent-item-desc">
                  {{ agent.desc }}
                </div>
              </div>
            </slot>
          </div>
        </slot>
      </div>
      <div class="list history-list" v-if="currentTab === 'history' && config.historyFlag">
        <slot name="history-list" :historyList="historyList">
          <div class="empty" v-if="historyList.length === 0">历史记录为空</div>
          <div
            class="history-item"
            v-for="(history, index) in historyList"
            :key="index"
            @click="() => selectHistory(history)"
          >
            <slot name="history-item" :history="history">
              <div class="history-item-label">
                <Message></Message>
                <span class="name">{{ history.title }}</span>
              </div>
              <div class="tools">
                <div class="tool delete" @click="removeHistory(history)">
                  <Delete />
                </div>
              </div>
            </slot>
          </div>
        </slot>
      </div>
    </div>
    <div class="current-agent">
      <slot name="title">
        <div class="chat-title">
          <Menu
            class="chat-title-menu"
            @click="isShowMenu = !isShowMenu"
            v-if="config.historyFlag || config.multipleAgentFlag"
          ></Menu>
          <span class="chat-title-name">{{ config.name }}</span>
        </div>
      </slot>
      <div class="messages-container" ref="messagesContainer">
        <div v-for="(message, index) in messages" :key="index" :class="['message', message.role]">
          <slot name="avatar">
            <div v-if="message.role === 'assistant'" class="avatar">
              <div class="ai-avatar">AI</div>
            </div>
          </slot>
          <div class="message-content">
            <!-- 渲染 -->
            <slot
              name="render-answer-content"
              :content="message.content"
              v-if="message.role === 'assistant'"
            >
              <answer-chat-content
                :text="message.content"
                :streaming="isStreaming"
              ></answer-chat-content>
            </slot>
            <slot name="render-question-content" :content="message.content" v-else>
              <user-chat-content :message="message" />
            </slot>
            <div class="message-info">
              <div class="message-time">
                {{ formatDate(message.timestamp) }}
              </div>
              <div class="message-tools" v-if="message.role === 'assistant'">
                <slot name="message-tools">
                  <div class="message-tool-group">
                    <span
                      class="message-tool"
                      v-if="message.content"
                      @click="copyMessageContent(message.content)"
                    >
                      <i>
                        <Copy></Copy>
                      </i>
                    </span>
                    <span class="message-tool" v-if="showRetry(index)" @click="retry">
                      <i>
                        <Retry></Retry>
                      </i>
                    </span>
                  </div>
                </slot>
              </div>
            </div>
          </div>
        </div>
        <div v-if="isLoading" class="message assistant">
          <slot name="avatar">
            <div class="avatar">
              <div class="ai-avatar">AI</div>
            </div>
          </slot>
          <div class="message-content">
            <slot name="thinking">
              <Thinking />
            </slot>
          </div>
        </div>
      </div>
      <slot
        name="input"
        :value="inputMessage"
        :sendMessage="sendMessage"
        :isLoading="isLoading"
        :isStreaming="isStreaming"
      >
        <div class="input-container">
          <input
            type="file"
            multiple
            ref="fileInput"
            style="display: none"
            @change="handleFileChange"
          />
          <div class="input-files">
            <template v-for="file in uploadFiles">
              <div class="file-item" :style="{ '--progress': file.progress + '%' }">
                <div class="file-progress uploading" v-if="file.status === 'uploading'"></div>
                <div class="file-progress success" v-else-if="file.status === 'success'"></div>
                <div class="file-progress error" v-else></div>
                <div class="file-name">{{ file.name }}</div>
                <div class="file-delete" @click="handleFileRemove(file)">
                  <SimpleDelete />
                </div>
              </div>
            </template>
          </div>
          <div class="input-tools">
            <template v-for="tool in inputTools">
              <button
                v-if="tool.showFlag"
                :class="['tool', tool.active ? 'active' : '']"
                @click="() => tool.click()"
              >
                <div class="tool-icon">
                  <Component :is="tool.icon" />
                </div>
                <div class="tool-name">{{ tool.name }}</div>
              </button>
            </template>
          </div>
          <div :class="['input-box', isLoading || isStreaming ? 'disabled' : '']">
            <textarea
              v-model="inputMessage"
              @keydown="handleKeyPress"
              placeholder="请输入您的问题..."
              :disabled="isLoading || isStreaming"
            ></textarea>
            <button
              class="input-button send"
              @click="sendMessage()"
              v-if="!isStreaming"
              :disabled="isLoading || !inputMessage.trim()"
            >
              <Send></Send>
            </button>
            <button class="input-button stop" @click="stopMessage()" v-else>
              <Stop></Stop>
            </button>
          </div>
        </div>
      </slot>
    </div>
  </div>
</template>

<style scoped>
.chat-container {
  --chat-font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', system-ui;
  --chat-background-color: #f9f9fb;
  --chat-primary-color: #6c5dd3;
  --chat-primary-color-hover: #5a4dc2;
  --chat-primary-border-color: #e5e5f6;
}

@media (prefers-color-scheme: dark) {
  .chat-container {
    --chat-background-color: #2a2a33;
    --chat-primary-color: #dddbe8;
    --chat-primary-color-hover: #d6d0fd;
    --chat-primary-border-color: #5345af;
  }
}

::-webkit-scrollbar {
  width: 1.2vw;
  max-width: 8px;
  height: 0;
  background-color: var(--chat-primary-border-color);
}

::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 2px var(--chat-primary-color);
  border-radius: 5px;
  background-color: var(--chat-background-color);
}

::-webkit-scrollbar-thumb {
  border-radius: 5px;
  -webkit-box-shadow: inset 0 0 6px var(--chat-primary-color);
  background-color: var(--chat-primary-color);
}

.chat-container {
  position: relative;
  display: flex;
  width: 100%;
  flex-direction: row;
  height: 100vh;
  margin: 0 auto;
  background: var(--chat-background-color);
  font-family: var(--chat-font-family), sans-serif;
}

.chat-menu {
  position: relative;
  height: 100%;
  width: 18%;
  min-width: 200px;
  max-width: 400px;
  border-right: 1px solid #e0e0e0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 5px 10px;
  transition: all 0.4s ease-in-out;
}

.chat-menu.hidden {
  max-width: 0 !important;
  min-width: 0 !important;
  padding: 0;
  opacity: 0;
  transform: translateX(-100px);
}

.list {
  width: 100%;
  opacity: 1;
  transition: opacity 0.2s ease-in-out;
  overflow: hidden;
}

.chat-menu.hidden .list {
  opacity: 0 !important;
}

.history-list .empty {
  text-align: center;
  margin-top: 20px;
  font-size: 14px;
  color: #555;
  line-height: 1.5;
}

.chat-menu-tabs {
  display: flex;
  margin-bottom: 10px;
}

.chat-menu-title {
  flex: 1;
  text-align: center;
  padding: 8px 0;
  color: #222;
  cursor: pointer;
  transition: all 0.4s ease-in-out;
  border-bottom: 2px solid transparent;
  box-sizing: border-box;
  position: relative;
  user-select: none;
}

.chat-menu-title::after {
  content: '';
  position: absolute;
  bottom: -1px; /* 对齐父元素底部 */
  left: 0;
  right: 0;
  height: 1.5px;
  background: #e0e0e0;
  transition: inherit;
}

.chat-menu-title.active {
  color: var(--chat-primary-color);
  border-bottom-color: var(--chat-primary-color); /* 覆盖伪元素样式 */
}

.chat-menu-title.active::after {
  background: transparent; /* 隐藏默认下划线 */
}

.chat-menu-title:hover {
  color: var(--chat-primary-color-hover);
}

.history-item {
  padding: 5px 8px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  border-radius: 5px;
  color: #222;
  fill: #222;
  margin: 4px 0;
  min-width: 50px !important;
  user-select: none;
}

.history-item:hover {
  background-color: var(--chat-primary-color-hover);
  color: white;
  fill: white;
}

.history-item .history-item-label {
  white-space: nowrap;
  font-size: 0.94em;
  display: flex;
  align-items: center;
  width: 100%;
  gap: 5px;
}

.history-item .history-item-label svg {
  width: 16px !important;
}

.history-item .history-item-label .name {
  width: calc(100% - 20px);
  overflow: hidden;
  text-overflow: ellipsis;
}

.history-item .tools {
  display: flex;
  align-items: center;
  gap: 5px;
  transition: all 0.2s ease-in-out;
  opacity: 0;
}

.history-item .tools svg {
  width: 15px !important;
  height: 15px !important;
  fill: #f2f2f2;
}

.history-item:hover .tools {
  opacity: 1;
}

.history-item .tools .tool {
  transition: all 0.2s ease-in-out;
}

.history-item .tools .tool:hover {
  fill: #fff;
  transform: scale(1.1);
}

.agent-item {
  padding: 8px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  border-radius: 5px;
  color: #222;
  margin: 4px 0;
  min-width: 50px !important;
  user-select: none;
}

.agent-item.active {
  background-color: var(--chat-primary-color);
  color: white !important;
}

.agent-item:hover {
  background-color: var(--chat-primary-color-hover);
  color: white;
}

.agent-item-icon {
  width: 40px !important;
  height: 40px !important;
  background-color: var(--chat-primary-border-color);
  border-radius: 20%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
}

.agent-item-icon img,
.default-icon {
  width: 40px !important;
  height: 30px !important;
  fill: var(--chat-primary-color) !important;
}

.agent-item-icon .default-icon svg {
  width: 40px !important;
  height: 30px !important;
}

.agent-item-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.agent-item-content .agent-item-name {
  font-size: 1em;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--chat-primary-color-hover);
}

.agent-item:hover .agent-item-content .agent-item-name,
.agent-item:hover .agent-item-content .agent-item-desc,
.agent-item.active .agent-item-content .agent-item-name,
.agent-item.active .agent-item-content .agent-item-desc {
  color: #fff;
}

.agent-item-content .agent-item-desc {
  font-size: 0.76em;
  font-weight: 400;
  color: var(--chat-primary-color-hover);
}

.current-agent {
  flex: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.chat-title {
  background: linear-gradient(20deg, var(--chat-background-color) 0%, #ffffff 100%);
  color: #222;
  padding: 1.8vh 20px;
  font-size: clamp(18px, 2vh, 22px);
  font-weight: 600;
  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  gap: 10px;
}

.chat-title-menu {
  padding: 4px;
  margin-right: 10px;
  cursor: pointer;
  width: 25px;
  height: 25px;
  fill: #222;
  transition: all 0.2s ease;
}

.chat-title-menu:hover {
  opacity: 0.6;
}

.chat-title-name {
  user-select: none;
}

.messages-container {
  flex: 1;
  overflow-y: auto;
  padding: 3vw;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.message {
  position: relative;
  display: flex;
  align-items: flex-start;
  max-width: 80%;
  gap: 8px;
  opacity: 0;
  animation: fadeIn 0.6s forwards;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.message.user {
  align-self: flex-end;
  flex-direction: row-reverse;
}

.message.assistant {
  align-self: flex-start;
}

.avatar {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ai-avatar {
  width: 35px;
  height: 35px;
  background-color: var(--chat-primary-color);
  color: var(--chat-primary-border-color);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 14px;
  user-select: none;
}

.message-content {
  flex: 1;
  word-break: break-word;
  padding: 8px 16px 12px 16px;
  border-radius: 12px;
  min-width: 200px;
}

.message.assistant .message-content {
  background-color: white;
  color: #333;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.message.user .message-content {
  background-color: var(--chat-primary-color);
  color: white;
}

.message-info {
  width: 100%;
  height: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 15px;
}

.message-time {
  font-size: 0.75rem;
  opacity: 0.7;
  margin-top: 4px;
  text-align: left;
  width: 55px;
}

.message-tools {
  width: calc(100% - 50px);
}

.message-tool-group {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
}

.message-tool {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 14px;
  width: 14px;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.2s;
}

.message-tool i,
svg {
  display: flex;
  color: currentColor;
  fill: currentColor;
  width: 100%;
  height: 100%;
}

.message-tool:hover svg {
  color: var(--chat-primary-color);
  fill: var(--chat-primary-color);
}

.input-container {
  display: flex;
  padding: 0 20px;
  align-items: stretch;
  overflow: hidden;
  flex-direction: column;
}

.input-files {
  display: flex;
  align-items: center;
  gap: 10px;
  overflow-x: auto;
  padding: 4px 0 4px 0;
  margin-bottom: 2px;
  height: fit-content;
}

.input-files .file-item {
  --progress: 0%;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex-shrink: 0;
  padding: 1px 8px;
  margin: 4px 1px;
  border-radius: 10px;
  border: 1px solid #e0e0e0;
  user-select: none;
  cursor: pointer;
  background: var(--chat-background-color);
  box-shadow: 0 0 1px rgba(0, 0, 0, 0.1);
  transition: all 0.4s;
  color: var(--chat-primary-color-hover);
  overflow: hidden;
}

.input-files .file-item .file-progress {
  width: 100%;
  aspect-ratio: 1 / 1;
  position: absolute;
  z-index: 0;
  border-radius: 42%;
}

.input-files .file-item .file-progress.success {
  background: var(--chat-primary-border-color);
}

.input-files .file-item .file-progress.error {
  background: #ff8888;
}

.input-files .file-item .file-progress.uploading {
  --translate-x: calc(var(--progress) - 100%);
  background: var(--chat-primary-border-color);
  animation: rotation 4s linear infinite;
  transform-origin: calc(var(--progress) - 50%);
}

@keyframes rotation {
  from {
    transform: rotate(0) translateX(var(--translate-x));
  }

  to {
    transform: rotate(360deg) translateX(var(--translate-x));
  }
}

.input-files .file-item:hover {
  color: var(--chat-primary-color);
}

.input-files .file-item .file-name {
  font-size: 0.95em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 150px;
  z-index: 2;
}

.input-files .file-item .file-delete {
  width: 16px;
  height: 16px;
  margin-top: 4px;
  padding: 0 2px;
  z-index: 2;
}

.input-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
  overflow-x: auto;
  padding: 4px 0 8px 0;
  white-space: nowrap;
}

.input-tools .tool {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px 10px;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid #e0e0e0;
  box-shadow: 0 0 1px rgba(0, 0, 0, 0.1);
  transition: all 0.2s;
  background-color: var(--chat-background-color);
  font-size: 0.94em;
  color: var(--chat-primary-color);
  fill: #555;
  user-select: none;
  flex-shrink: 0;
  width: fit-content;
}

.input-tools .tool .tool-name {
  display: flex;
  align-items: center;
  vertical-align: center;
  margin-bottom: 1px;
}

.input-tools .tool.active {
  background-color: var(--chat-primary-border-color);
  color: var(--chat-primary-color);
}

.input-tools .tool svg {
  width: 16px;
  height: 16px;
  margin-right: 0.3em;
}

.input-box {
  position: relative;
  flex: 1;
  padding: 1vh;
  border: 1px solid #e0e0e0;
  border-radius: 12px;
  resize: none;
  font-size: 1rem;
  line-height: 1.5;
  background: transparent;
  display: flex;
  background: linear-gradient(-10deg, var(--chat-background-color) 0%, #ffffff 100%);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  margin-bottom: 10px;
}

.input-box.disabled {
  background-color: #fdfdfd;
}

textarea {
  font-family: var(--chat-font-family);
  flex: 1;
  overflow-y: auto;
  border: none;
  resize: none;
  background: transparent;
  color: #000;
  font-size: 1em;
  min-height: clamp(40px, 8vh, 200px);
  field-sizing: content;
}

textarea:focus {
  outline: none;
}

textarea:disabled {
  background-color: #fdfdfd;
  color: #555;
}

.input-button {
  position: absolute;
  right: 8px;
  bottom: 6px;
  width: 32px;
  height: 32px;
  background-color: var(--chat-primary-color);
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 500;
  transition: background-color 0.2s;
  padding: 5px;
}

.input-button svg {
  width: 100%;
  height: 100%;
}

.input-button.stop {
  background-color: #a87220;
  padding: 8px;
}

.input-button:hover:not(:disabled) {
  background-color: var(--chat-primary-color-hover);
}

.input-button.stop:not(:disabled) {
  background-color: #f1af58;
}

.input-button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}

@media (max-width: 768px) {
  .message {
    max-width: 100%;
  }

  .avatar {
    visibility: hidden;
    position: absolute;
    top: -100%;
    left: -100%;
    width: 0;
    height: 0;
    overflow: hidden;
  }

  .chat-menu {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 9999;
    width: 60% !important;
    height: 100vh;
    padding: 10px 4px;
    transform: translateX(-100%);
    transition: transform 0.5s ease;
    box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
    background: var(--chat-background-color);
  }

  .chat-menu:not(.hidden) {
    transform: translateX(0);
  }

  .chat-menu.hidden {
    transform: translateX(-100%);
  }

  .chat-menu.hidden .agent-list {
    opacity: 1;
  }

  .input-button {
    min-height: 30px;
    height: 4.3vh;
    width: auto;
  }
}

@media (prefers-color-scheme: dark) {
  .agent-item:hover .agent-item-content .agent-item-name,
  .agent-item:hover .agent-item-content .agent-item-desc,
  .agent-item.active .agent-item-content .agent-item-name,
  .agent-item.active .agent-item-content .agent-item-desc {
    color: #222;
  }

  .chat-menu-title {
    color: #888;
  }

  .history-list .empty {
    color: #ccc;
  }

  .message.assistant .message-content {
    background-color: #232323;
    color: white;
    box-shadow: 0 1px 2px var(--chat-primary-color);
    border: 1px solid var(--chat-primary-color);
  }

  .chat-title {
    color: white;
    background: linear-gradient(-20deg, var(--chat-background-color) 0%, #434343 100%);
  }

  .chat-title-menu {
    fill: white;
  }

  .input-box {
    background: linear-gradient(10deg, var(--chat-background-color) 0%, #434343 100%);
  }

  textarea {
    color: white;
  }

  textarea:disabled {
    background-color: transparent;
    color: #ddd;
  }

  .input-button {
    color: black;
  }

  .message.user .message-content {
    color: black;
  }

  .history-item {
    color: #f2f2f2;
    fill: #f2f2f2;
  }

  .history-item:hover {
    color: #222;
    fill: #222;
  }

  .history-item .tools svg {
    fill: #222;
  }

  .input-files .file-item .file-progress.error {
    background: #dd4444;
  }
}
</style>
